package com.xz.audit.service.impl;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xz.audit.domain.*;
import com.xz.audit.dto.AuditDto;
import com.xz.audit.dto.AuditInfoDto;
import com.xz.audit.service.IAuditNodeService;
import com.xz.audit.service.IAuditProcessService;
import com.xz.audit.service.IProcessApproveService;
import com.xz.common.core.domain.AjaxResult;
import com.xz.common.core.domain.entity.SysRole;
import com.xz.common.core.domain.entity.SysUser;
import com.xz.common.core.domain.model.LoginUser;
import com.xz.common.exception.ServiceException;
import com.xz.common.utils.DateUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xz.common.utils.SecurityUtils;
import org.aspectj.weaver.loadtime.Aj;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.xz.audit.mapper.ProcessInstanceMapper;
import com.xz.audit.service.IProcessInstanceService;
import org.springframework.util.CollectionUtils;

/**
 * 流程实例Service业务层处理
 *
 * @author xz
 * @date 2024-01-15
 */
@Service
public class ProcessInstanceServiceImpl extends ServiceImpl<ProcessInstanceMapper, ProcessInstance> implements IProcessInstanceService {
    @Autowired
    private ProcessInstanceMapper processInstanceMapper;
    @Autowired
    private IAuditNodeService auditNodeService;
    @Autowired
    private IProcessApproveService iProcessApproveService;
    @Autowired
    private IAuditProcessService iAuditProcessService;


    //成功
    public static final Integer  SUCCESS= 1;
    //最后节点
    public static final Integer  FINAL_NODE= 3;
    //第一节点，重新发起
    public static final Integer  FIRST_NODE= 4;
    /**
     * 查询流程实例
     *
     * @param id 流程实例主键
     * @return 流程实例
     */
    @Override
    public ProcessInstance selectProcessInstanceById(Long id) {
        return processInstanceMapper.selectProcessInstanceById(id);
    }

    /**
     * 查询流程实例列表
     *
     * @param processInstance 流程实例
     * @return 流程实例
     */
    @Override
    public List<ProcessInstance> selectProcessInstanceList(ProcessInstance processInstance) {
        return processInstanceMapper.selectProcessInstanceList(processInstance);
    }

    /**
     * 新增流程实例
     *
     * @param auditInfoDto 流程实例
     * @return 结果
     */
    @Override
    public Boolean insertProcessInstance(AuditInfoDto auditInfoDto) {
        try {
            //查询当前订单是否已经开始审核
            List<ProcessInstance> auditInfoList = baseMapper.selectList(new QueryWrapper<ProcessInstance>().eq("biz_no", auditInfoDto.getBizNo()).eq("biz_type", auditInfoDto.getBizType()));
            if (!CollectionUtils.isEmpty(auditInfoList) && auditInfoDto.getStatus()==1) {
                throw new ServiceException("审批已发起,请务重复发起");
            }
            //查询流程节点
            List<AuditProcess> auditProcessList = iAuditProcessService.list(new QueryWrapper<AuditProcess>().eq("biz_type", auditInfoDto.getBizType()).eq("status", 0));
            if (CollectionUtils.isEmpty(auditProcessList)) {
                throw new ServiceException("流程不存在");
            }
            //校验流程是否有有配置节点
            AuditProcess auditProcess = auditProcessList.get(0);
            //查询流程节点
            List<AuditNode> nodeList = auditNodeService.list(new QueryWrapper<AuditNode>().eq("process_id", auditProcess.getId()).orderByAsc("audit_sort"));
            if(CollectionUtils.isEmpty(nodeList)){
                throw new ServiceException("流程不存在");
            }
            //第一节点
            AuditNode auditNode = nodeList.get(0);

            if(auditInfoDto.getStatus()==2){//重新发起
                ProcessInstance initiateAuditInfo=auditInfoList.get(0);
                initiateAuditInfo.setAuditStatus(1);
                processInstanceMapper.updateProcessInstance(initiateAuditInfo);
                //发起节点
                ProcessApprove processApprove = initiatingDataFilling(SecurityUtils.getLoginUser().getUser(), initiateAuditInfo);
                iProcessApproveService.insertProcessApprove(processApprove);
                //插入第一审核节点
                ProcessApprove auditProcessApprove = auditDataFilling(SecurityUtils.getLoginUser().getUser(), initiateAuditInfo);
                iProcessApproveService.insertProcessApprove(auditProcessApprove);
                return true;
            }else{
                //新增流程实例
                ProcessInstance initiateAuditInfo = processInstanceDataFilling(SecurityUtils.getLoginUser().getUser(), auditInfoDto, auditNode);
                int insertProcessInstance = processInstanceMapper.insertProcessInstance(initiateAuditInfo);
                if(insertProcessInstance>0){
                    //新增流程审批信息
                    //发起节点
                    ProcessApprove processApprove = initiatingDataFilling(SecurityUtils.getLoginUser().getUser(), initiateAuditInfo);
                    iProcessApproveService.insertProcessApprove(processApprove);
                    //插入第一审核节点
                    ProcessApprove auditProcessApprove = auditDataFilling(SecurityUtils.getLoginUser().getUser(), initiateAuditInfo);
                    iProcessApproveService.insertProcessApprove(auditProcessApprove);
                    return true;
                }
            }


            return false;

        }catch (Exception e){
            throw new ServiceException("发起审批失败");
        }
    }
    /**
     * 数据填充--发起数据填充--流程实例
     * @param auditInfoDto
     * @return
     */
    public ProcessInstance processInstanceDataFilling(SysUser sysUser, AuditInfoDto auditInfoDto,AuditNode auditNode){
        ProcessInstance info=new ProcessInstance();
        info.setBizNo(auditInfoDto.getBizNo());
        info.setNodeId(auditNode.getId());
        info.setAuditStatus(1);
        info.setTenantId(sysUser.getTenantId());
        info.setCreateTime(new Date());
        info.setCreateBy(SecurityUtils.getUserId());
        info.setBizType(auditInfoDto.getBizType());
        info.setAuditTypeMethod(auditNode.getAuditMethod());
        info.setAuditTypeId(auditNode.getAuditId());
        info.setAuditTypeName(auditNode.getAuditName());
        info.setNodeName(auditNode.getNodeName());
        return info;
    }
    /**
     * 数据填充--发起数据填充--发起节点
     * @param processInstance
     * @return
     */
    public ProcessApprove initiatingDataFilling(SysUser sysUser,ProcessInstance processInstance){
        ProcessApprove info=new ProcessApprove();
        info.setBizNo(processInstance.getBizNo());
        info.setProcessInstanceId(processInstance.getId());
        info.setAuditStatus(2);
        info.setNodeId(0L);
        info.setBizType(processInstance.getBizType());
        info.setAuditId(sysUser.getUserId());
        info.setAuditName(sysUser.getUserName());
        info.setAuditTime(new Date());
        info.setTenantId(sysUser.getTenantId());
        info.setCreateTime(new Date());
        info.setCreateBy(SecurityUtils.getUserId());
        return info;
    }
    /**
     * 数据填充--发起数据填充--待审核节点
     * @param processInstance
     * @return
     */
    public ProcessApprove auditDataFilling(SysUser sysUser,ProcessInstance processInstance){
        ProcessApprove info=new ProcessApprove();
        info.setBizNo(processInstance.getBizNo());
        info.setProcessInstanceId(processInstance.getId());
        info.setAuditStatus(1);
        info.setNodeId(processInstance.getNodeId());
        info.setBizType(processInstance.getBizType());
        if(processInstance.getAuditTypeMethod()==2){
            info.setAuditId(processInstance.getAuditTypeId());
            info.setAuditName(processInstance.getAuditTypeName());
        }
        info.setTenantId(sysUser.getTenantId());
        info.setCreateTime(new Date());
        info.setCreateBy(SecurityUtils.getUserId());
        return info;
    }
    /**
     * 修改流程实例
     *
     * @param auditDto 流程实例
     * @return 结果
     */
    @Override
    public int updateProcessInstance(AuditDto auditDto) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        //获取当前审核节点
        List<ProcessInstance> auditInfoList = baseMapper.selectList(new QueryWrapper<ProcessInstance>().eq("biz_no", auditDto.getBizNo()).ne("audit_status",2).eq("biz_type",auditDto.getBizType()));
        if(CollectionUtils.isEmpty(auditInfoList)){
            throw new ServiceException("审核失败");
        }
        ProcessInstance processInstance = auditInfoList.get(0);
        //修改审核流程
        List<ProcessApprove> processApproveList = iProcessApproveService.list(new QueryWrapper<ProcessApprove>().eq("biz_no", auditDto.getBizNo()).eq("process_instance_id", processInstance.getId()).eq("audit_status", 1));
        if(CollectionUtils.isEmpty(processApproveList)){
            throw new ServiceException("审核失败");
        }
        processInstance.setUpdateBy(loginUser.getUserId());
        processInstance.setUpdateTime(new Date());
        ProcessApprove approve = processApproveList.get(0);
        approve.setUpdateTime(new Date());
        approve.setAuditTime(new Date());

        approve.setUpdateBy(loginUser.getUserId());
        approve.setAuditId(loginUser.getUserId());
        approve.setAuditStatus(auditDto.getAuditStatus()==1?2:3);
        approve.setAuditName(loginUser.getUsername());
        approve.setAuditNote(auditDto.getRemark());
        int updated = iProcessApproveService.updateProcessApprove(approve);
        if(updated==0){
            throw new ServiceException("审核失败");
        }
        //校验当前节点
        AuditNode serviceById = auditNodeService.getById(processInstance.getNodeId());
        if(Objects.isNull(serviceById)){
            throw new ServiceException("流程不存在");
        }
        List<AuditNode> auditNodeList=null;
        if(auditDto.getAuditStatus()==2){//拒绝
            //是否是第一节点
            auditNodeList = auditNodeService.list(new QueryWrapper<AuditNode>().eq("process_id",serviceById.getProcessId()).lt("audit_sort", serviceById.getAuditSort()).orderByDesc("audit_sort"));
            if(CollectionUtils.isEmpty(auditNodeList)){
                processInstance.setAuditStatus(4);
                baseMapper.updateProcessInstance(processInstance);
                return FIRST_NODE;
            }
        }else{
            //校验是否有下一节点
            auditNodeList = auditNodeService.list(new QueryWrapper<AuditNode>().eq("process_id",serviceById.getProcessId()).gt("audit_sort", serviceById.getAuditSort()).orderByAsc("audit_sort"));
            if(CollectionUtils.isEmpty(auditNodeList)){
                processInstance.setAuditStatus(2);
                baseMapper.updateProcessInstance(processInstance);
                return FINAL_NODE;
            }
        }
        //生成待审核信息
        AuditNode auditNode = auditNodeList.get(0);
        processInstance.setNodeId(auditNode.getId());
        processInstance.setNodeName(auditNode.getNodeName());
        processInstance.setAuditTypeId(auditNode.getAuditId());
        processInstance.setAuditTypeName(auditNode.getAuditName());
        processInstance.setAuditTypeMethod(auditNode.getAuditMethod());
        int updateProcessInstance = baseMapper.updateProcessInstance(processInstance);
        if(updateProcessInstance==0){
            throw new ServiceException("审核失败");
        }
        //生成待审核信息
        ProcessApprove processApprove = auditDataFilling(loginUser.getUser(), processInstance);
        int insertProcessApprove = iProcessApproveService.insertProcessApprove(processApprove);
        if(insertProcessApprove==0){
            throw new ServiceException("审核失败");
        }
        return SUCCESS;
    }

    /**
     * 批量删除流程实例
     *
     * @param ids 需要删除的流程实例主键
     * @return 结果
     */
    @Override
    public int deleteProcessInstanceByIds(Long[] ids) {
        return processInstanceMapper.deleteProcessInstanceByIds(ids);
    }

    /**
     * 更新流程状态
     *
     * @return 结果
     */
    @Override
    public int updateProcessInstanceauditStatus(Integer auditStatus,String bizNo) {
        return processInstanceMapper.updateProcessInstanceauditStatus(auditStatus,bizNo);
    }
    /**
     * 审核权限
     * @param id
     * @return
     */
    @Override
    public ProcessInstance iAuditInfoService(Long deptId,Long id, SysUser sysUser,List<ProcessInstance> auditInfoList) {
        ProcessInstance auditInfo=new ProcessInstance();
        List<SysRole> roles = sysUser.getRoles();
        Long roleId;
        if(!CollectionUtils.isEmpty(roles)){
            roleId= roles.get(0).getRoleId();
        } else {
            roleId = null;
        }
        List<ProcessInstance> list = auditInfoList.stream().filter(i -> i.getBizNo().equals(id.toString())).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(list)){
            ProcessInstance info = list.get(0);
            auditInfo.setNodeName(info.getNodeName());
            auditInfo.setAuditStatus(info.getAuditStatus());



            if(info.getAuditTypeMethod()==1){//1.角色 2.审核人 3.部门
                if(deptId==null){
                    if(roleId!=null&& Objects.equals(info.getAuditTypeId(), roleId)){
                        auditInfo.setAuditBut(1);
                    }
                }else {
                    if(deptId.equals(sysUser.getDeptId())){
                        if(roleId!=null&& Objects.equals(info.getAuditTypeId(), roleId)){
                            auditInfo.setAuditBut(1);
                        }
                    }
                }

            }
            if(info.getAuditTypeMethod()==2){
                if(sysUser.getUserId().equals(info.getAuditTypeId())){
                    auditInfo.setAuditBut(1);
                }
            }
            if(info.getAuditTypeMethod()==3){
                if(sysUser.getDeptId().equals(info.getAuditTypeId())){
                    auditInfo.setAuditBut(1);
                }
            }
        }
        return auditInfo;
    }
}
